import sublime, sublime_plugin

breakpoint_active_icon = "Packages/sourse_jump/breakpoint_active.png"
breakpoint_current_icon = "Packages/sourse_jump/breakpoint_current.png"
g_all_file_breaks_info = [] #FileBPinfo

ACTIVE = 1
REMOVE = 2
CURRENT = 3

g_point_idx = -1
current_point_idx = -1
effective_point_numbers = []

class BreakPoint():
	def __init__(self, _region, _row):
		self.region = _region #存放所有的break断点sublime.Region
		self.row = _row
		self.point_number = 0
		

	def __eq__(self, other):
		return self.region == other.region 

	def __str__(self):
		return self.fname + " row:" + str(self.row)

class FileBPinfo():
	def __init__(self, fname, view, breaks = []):
		self.fname = fname
		self.view = view
		self.breaks = breaks


def get_filebpinfo_by_fname(fname):
	for x in g_all_file_breaks_info:
		if x.fname == fname:
			return x
	return None

def get_filebpinfo_by_view(v):
	for x in g_all_file_breaks_info:
		if x.view == v:
			return x
	return None


def get_info_by_current_point_idx(idx):
	for info in g_all_file_breaks_info:
		for b in info.breaks:
			if b.point_number == idx:
				return info
	return None


def get_rows_num(v, lines):#获得行号
		if not type(lines) == list:
			lines = [lines]
		return [v.rowcol(line.begin())[0] for line in lines]

def computed_effective_point_numbers():
	global effective_point_numbers
	effective_point_numbers.clear()
	for info in g_all_file_breaks_info:
		if info.view.is_valid() == False and len(info.breaks) == 0: #view已关闭并且view内没有设置标记点
			g_all_file_breaks_info.remove(info)
	for info in g_all_file_breaks_info:
		for b in info.breaks:
			effective_point_numbers.append(b.point_number)


def update_break_point():
	global current_point_idx
	computed_effective_point_numbers()
	for info in g_all_file_breaks_info:
		if info.view.is_valid() == True:
			info.view.erase_regions('breakpoint_active')
			info.view.erase_regions('breakpoint_current')
			current = []
			other = []
			for b in info.breaks:
				if b.point_number == current_point_idx:
					current.append(b.region)
				else:
					other.append(b.region)
			info.view.add_regions('breakpoint_active', other, "breakpoint_scope", icon=breakpoint_active_icon, flags=sublime.HIDDEN)
			info.view.add_regions('breakpoint_current', current, "breakpoint_scope", icon=breakpoint_current_icon, flags=sublime.HIDDEN)


code = "flag-instance-code"
# v = self.window.open_file("C:\\Users\\cmj\\Desktop\\data_struct\\main.cpp")
class FlagCommand(sublime_plugin.WindowCommand):
	
	instance_name = code

	def run(self):
		current_view = self.window.active_view()
		full_file_name = current_view.file_name()
		print("add break point:", full_file_name)
		self.set_break_point(current_view, full_file_name)
	
	def set_break_point(self, view, fname):
		global g_point_idx
		l = self.get_view_lines(view)
		print("row:", get_rows_num(view, l)[0])
		breaks = [BreakPoint(b, get_rows_num(view, l)[0]) for b in l]
		info = get_filebpinfo_by_view(view)
		if info == None:
			for x in breaks:
				g_point_idx = g_point_idx + 1
				x.point_number = g_point_idx
			g_all_file_breaks_info.append(FileBPinfo(fname, view, breaks))
		else:
			for b in breaks:
				if b not in info.breaks:
					g_point_idx = g_point_idx + 1
					b.point_number = g_point_idx
					info.breaks.append(b)
				else:
					info.breaks.remove(b)
		update_break_point()

	def get_view_lines(self, v):
		lines = []
		regions = v.sel()
		for i in range(len(regions)):
			lines.extend(v.split_by_newlines(regions[i]))
		return [v.line(line) for line in lines]

	def on_modified(self, v):
		current_select = self.get_view_lines(v)
		rows = get_rows_num(v, current_select);
		

	def on_load(self, v): #监听打开文件
		full_file_name = v.file_name()
		finfo = get_filebpinfo_by_fname(full_file_name)
		if finfo == None:
			return
		finfo.view = v;
		update_break_point()


def fouse_point(cls):
	info = get_info_by_current_point_idx(current_point_idx)
	if info == None:
		return
	v = cls.window.open_file(info.fname)
	info.view = v
	for b in info.breaks:
		if b.point_number == current_point_idx:
			info.view.show(b.region)


class JumpNextPointCommand(sublime_plugin.WindowCommand):

	def run(self):
		global current_point_idx, effective_point_numbers
		computed_effective_point_numbers()
		print(effective_point_numbers)
		if current_point_idx in effective_point_numbers:
			idx = effective_point_numbers.index(current_point_idx)
			if idx == len(effective_point_numbers) - 1:
				current_point_idx = effective_point_numbers[0]
			else:
				current_point_idx = effective_point_numbers[idx + 1]
		elif len(effective_point_numbers) > 0:
			current_point_idx = effective_point_numbers[0]
		print("JumpNextPoint:", current_point_idx)
		update_break_point()
		fouse_point(self)

class JumpPrevPointCommand(sublime_plugin.WindowCommand):

	def run(self):
		global current_point_idx, effective_point_numbers
		computed_effective_point_numbers()
		print(effective_point_numbers)
		if current_point_idx in effective_point_numbers:
			idx = effective_point_numbers.index(current_point_idx)
			if idx == 0:
				current_point_idx = effective_point_numbers[len(effective_point_numbers) - 1]
			else:
				current_point_idx = effective_point_numbers[idx - 1]
		elif len(effective_point_numbers) > 0:
			current_point_idx = effective_point_numbers[0]
		print("JumpPrevPoint:", current_point_idx)
		update_break_point()
		fouse_point(self)


def mount_plugin(_instance, callback_type):
	#此处使用挂载的方法往sublime中添加plugin，让plugin随着sublime自启动
	for x in sublime_plugin.all_callbacks[callback_type]:
		if hasattr(x, 'instance_name') and x.instance_name == _instance.instance_name:
			sublime_plugin.all_callbacks[callback_type].remove(x)


	sublime_plugin.all_callbacks[callback_type].append(_instance)

g_auto_save = FlagCommand(code)
mount_plugin(g_auto_save, "on_modified")
mount_plugin(g_auto_save, "on_load")